package com.ruiysoft.controller.wx;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruiysoft.controller.wx.api.WeChatApi;
import com.ruiysoft.controller.wx.api.service.WeChatApiService;
import com.ruiysoft.controller.wx.dto.DoTransferDto;
import com.ruiysoft.controller.wx.dto.OrderApplyRefundDto;
import com.ruiysoft.controller.wx.dto.OrderPaidDto;
import com.ruiysoft.controller.wx.dto.OrderPayDto;
import com.ruiysoft.controller.wx.dto.WeChatACodeDto;
import com.ruiysoft.controller.wx.res.JsSignResponse;
import com.ruiysoft.controller.wx.res.TokenResponse;
import com.ruiysoft.controller.wx.res.TransferredResponse;
import com.ruiysoft.entity.sys.SysMicroShop;
import com.ruiysoft.entity.sys.SysShopPayPlatform;
import com.ruiysoft.entity.sys.SysShopPersonnel;
import com.ruiysoft.pub.core.Result;
import com.ruiysoft.pub.core.ResultGenerator;
import com.ruiysoft.service.sys.clent.LoginContextUtil;
import com.ruiysoft.service.wechat.rabbit.PayCallbackSender;
import com.ruiysoft.sms.service.SmsService;
import com.ruiysoft.util.AESUtil;
import com.ruiysoft.util.WeChatUtil;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

/**
 * Created by 化增光 on 2018/11/3.
 */
@RestController
public class WeChatApiController implements WeChatApi {

    private static final Logger log = LoggerFactory.getLogger(WeChatApiController.class);

    private final ObjectMapper objectMapper;

    private final HttpServletRequest request;

    @Resource
    WeChatApiService weChatApiService;

    @Resource
    SmsService smsService;

//    @Resource
//    ISysShopPayPlatformService iSysShopPayPlatformService;

    @Resource
    PayCallbackSender payCallbackSender;

//    @Resource
//    ISysShopPersonnelService iSysShopPersonnelService;


    @org.springframework.beans.factory.annotation.Autowired
    public WeChatApiController(ObjectMapper objectMapper, HttpServletRequest request) {
        this.objectMapper = objectMapper;
        this.request = request;
    }

    @Override
    public Result<TokenResponse> getAccessToken() {
        String accept = request.getHeader("Accept");
        if (accept != null && accept.contains("application/json")) {
            try {
                SysShopPersonnel personnel = LoginContextUtil.instance().getEntryUser().getPersonnel();
                TokenResponse tokenResponse = weChatApiService.getAccessToken(LoginContextUtil.instance().getShopPayPlatformByAppId(personnel.getAppId()));
                return ResultGenerator.genSuccessResult(tokenResponse);
            } catch (Exception e) {
                log.error("Couldn't serialize response for content type application/json", e);
                return ResultGenerator.genFailResult(e.getMessage());
            }
        }
        return ResultGenerator.genAcceptResult("accept is :" + accept);
    }

    @Override
    public Result<JsSignResponse> jssign(@ApiParam(value = "", required = true) @RequestBody @Valid OrderPayDto order) {
        String accept = request.getHeader("Accept");
        if (accept != null && accept.contains("application/json")) {
            try {
                SysShopPersonnel personnel = LoginContextUtil.instance().getEntryUser().getPersonnel();
                JsSignResponse response = weChatApiService.jsSign(personnel, order);
                return ResultGenerator.genSuccessResult(response);
            } catch (Exception e) {
                log.error("Couldn't serialize response for content type application/json", e);
                return ResultGenerator.genFailResult(e.getMessage());
            }
        }

        return ResultGenerator.genAcceptResult("accept is :" + accept);
    }

    @Override
    public String payCallbackConfirm() {
        StringBuilder msgXml = new StringBuilder(600);
        BufferedReader br = null;
        try {
            System.out.println("微信支付成功回调!");
//            SysMicroShop shop = LoginContextUtil.instance().getEntryMicroShop();
//            log.info("店铺ID:---------"+shop.getId());
            br = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
            String rtn = null;
            while ((rtn = br.readLine()) != null) {
                msgXml.append(rtn);
            }
            String xml = msgXml.toString();
            log.info("微信支付回调内容:" + xml);
            if (StringUtils.isNotEmpty(xml)) {
                Map<String, String> result = WeChatUtil.readStringXmlOut(xml);
                if ("SUCCESS".equals(result.get("return_code"))) {
                    log.info("微信支付通信成功");
                    if ("VIP".equals(result.get("attach"))) {
                        payCallbackSender.sendVip(result.get("out_trade_no"), transferMessage(result));
                    } else {
                        payCallbackSender.send(result.get("out_trade_no"), transferMessage(result));
                    }

                } else {
                    log.info("微信支付通信失败");
                }
            } else {
                log.info("微信回调，微信传入信息为空");
            }

        } catch (Exception e) {
            log.error(e.getMessage());
        }

        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    @Override
    public String payRefundConfirm() {
        String returnXml = "";
        StringBuffer msgXml = new StringBuffer(600);
        BufferedReader br = null;
        try {
            System.out.println("微信退款成功回调!");
            br = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
            String rtn = null;
            while ((rtn = br.readLine()) != null) {
                msgXml.append(rtn);
            }
            String xml = msgXml.toString();
            log.info("微信退款回调内容:" + xml);
            if (StringUtils.isNotEmpty(xml)) {
                Map<String, String> result = WeChatUtil.readStringXmlOut(xml);
                if ("SUCCESS".equals(result.get("return_code"))) {
                    SysShopPayPlatform payPlatform = weChatApiService.selectShopPayPlatformByAppIdAndMachId(result.get("appid"), result.get("mch_id"));
                    String req_info = result.get("req_info");
                    String data = AESUtil.decryptData(req_info, payPlatform.getPayKey());
                    System.out.println("微信退款解析-->" + data);
                    Map<String, String> refundMap = WeChatUtil.readStringXmlOut(data);
                    payCallbackSender.sendRefund(refundMap.get("out_trade_no"), transferRefundMessage(refundMap));
                } else {
                    log.info("微信退款通信失败");
                }
                //异步回调接口
                returnXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                log.info("微信回调的应答: " + returnXml);
            } else {
                log.info("微信回调，微信传入信息为空");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return returnXml;
    }

    @Override
    public void wxacodeunlimit(HttpServletResponse response, @ApiParam(value = "", required = true) @RequestBody @Valid WeChatACodeDto aCodeDto) {
        if (log.isDebugEnabled()) {
            log.debug("wxacodeunlimit parameter is:{}", JSON.toJSONString(aCodeDto));
        }
        SysShopPersonnel personnel = LoginContextUtil.instance().getEntryUser().getPersonnel();
        SysMicroShop shop = LoginContextUtil.instance().getEntryMicroShop();
        SysShopPayPlatform payPlatform = LoginContextUtil.instance().getShopPayPlatformByAppId(personnel.getAppId());
        byte[] img = weChatApiService.wxacodeunlimit(shop.getId(), payPlatform.getAppId(), payPlatform.getSecret(), aCodeDto, personnel);
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            os.write(img);
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Result<TransferredResponse> doTransfer(@ApiParam(value = "", required = true) @RequestBody @Valid DoTransferDto dto) {
        try {
            TransferredResponse res = weChatApiService.doTransfer(dto);
            return ResultGenerator.genSuccessResult(res);

        } catch (Exception e) {
            return ResultGenerator.genFailResult(e.getMessage());
        }
    }

    private OrderApplyRefundDto transferRefundMessage(Map<String, String> refundMap) {
        Date refundTime = null;
        try {
            refundTime = DateUtils.parseDate(refundMap.get("refund_status"), Locale.TRADITIONAL_CHINESE, "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        OrderApplyRefundDto dto = new OrderApplyRefundDto()
                .setTransactionNo(refundMap.get("out_trade_no"))
                .setTransactionId(refundMap.get("transaction_id"))
                .setRefundId(refundMap.get("refund_id"))
                .setRefundAmount(new BigDecimal(refundMap.get("refund_fee")))
                .setResultCode(refundMap.get("refund_status"))
                .setRefundTime(refundTime);
        return dto;

    }

    private OrderPaidDto transferMessage(Map<String, String> result) {
        Date payTime = null;
        if (StringUtils.isNotBlank(result.get("time_end"))) {
            LocalDateTime localDateTime = LocalDateTime.parse(result.get("time_end"), DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            payTime = Date.from(instant);
        }

        OrderPaidDto dto = new OrderPaidDto()
                .setResultCode(result.get("result_code"))
                .setTransactionNo(result.get("out_trade_no"))
                .setPayAmount(new BigDecimal(result.get("total_fee")))
                .setTransactionId(result.get("transaction_id"))
                .setErrorMessage(result.get("err_code_des"))
                .setPayTime(payTime);
        return dto;
    }
}
